package com.mz;

import org.apache.http.HttpEntity;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/***
 * create by germmy@20171108
 * 功能：会起用线程池，对传入的url进行探测，并将每次返回结果打印出来
 * 注意：URL是必选入参、线程池数量是可选入参，默认为10
 */
public class MyClient implements Runnable {


    public static final int TIME_OUT = 10;
    public static final String HTTP_CODE_404 = "404";
    public static final String HTTP_CODE_403 = "403";//运维禁止
    public static final String HTTP_CODE_200 = "200";
    public static final String HTTP_CODE_405 = "405";
    public static final String HTTP_CODE_500 = "500";
    public static final String HTTP_CODE_UNKNOWN = "unknown";
    public static final String HTTP_CODE_TIMEOUT = "timeout";

    //被探测的url
    private String toBeDectedUrl = null;

    private int currentNum;

    public static void main(String args[]) {
        MyClient myClient = new MyClient();
        //1.校验参数
        myClient.init(args);
        //2.建立线程池
        ExecutorService executorService = Executors.newFixedThreadPool(ClientProperties.getThreadNums());
        for(int i=0;i<ClientProperties.getThreadNums();i++){//必须要用for循环，
            // 否则线程只会执行一次，换句话说，它只会从池子中拿出一个线程执行一下完事；
            // 这里还有个例子，假如循环是5次，但是池子中有10个线程，那效果就是每次池子中只拿出5个线程才搞这事，另外5个在休眠

            executorService.execute(myClient);
        }
        //3.进行调用
        executorService.shutdown();
    }


    public void test() throws Exception {
        String line;
        List<String> result = new ArrayList<String>();
        StringBuilder stringBuilder = new StringBuilder();
        CloseableHttpClient httpclient = HttpClients.createDefault();
        String url = "http://www.nonobank.com/Account/degreeCard";
//        String url = "http://www.nonobank.com/MicroSiteApi/UploadPhoneBook";
        HttpGet httpGet = new HttpGet(url);
        CloseableHttpResponse response1 = httpclient.execute(httpGet);
        try {
            System.out.println("返回状态为:" + response1.getStatusLine());
            InputStream inputStream = response1.getEntity().getContent();
            InputStreamReader reader = new InputStreamReader(
                    inputStream); // 建立一个输入流对象reader
            BufferedReader br = new BufferedReader(reader); // 建立一个对象，它把文件内容转成计算机能读懂的语言
            while ((line = br.readLine()) != null) {
                stringBuilder.append(line);
            }

            System.out.println("result:" + stringBuilder.toString());


            if (stringBuilder.toString().indexOf("升级维护(403)") > 0) {
                System.out.println("维护中");
            } else {
                System.out.println("网页正常");
            }


            if (response1.getStatusLine().toString().indexOf("200 OK") > 0) {
                System.out.println(url + "----连接成功");
            } else {
                if (response1.getStatusLine().toString().indexOf("404 Not Found") > 0) {
                    System.out.println(url + "----404");
                } else {
                    System.out.println(url + "----连接失败");
                }
            }
            HttpEntity entity1 = response1.getEntity();
            EntityUtils.consume(entity1);
        } finally {
            response1.close();
        }
    }


    public void invokeUrlSingle(String url) throws Exception {
        RequestConfig config = RequestConfig.custom()
                .setConnectTimeout(TIME_OUT * 1000)
                .setConnectionRequestTimeout(TIME_OUT * 1000)
                .setSocketTimeout(TIME_OUT * 1000).build();
//        CloseableHttpClient httpclient = HttpClients.createDefault();
        CloseableHttpClient httpclient =
                HttpClientBuilder.create().setDefaultRequestConfig(config).build();
        HttpGet httpGet = new HttpGet(url);
        CloseableHttpResponse response1 = httpclient.execute(httpGet);

        try {
            System.out.println("返回状态为:" + response1.getStatusLine());
            if (response1.getStatusLine().toString().indexOf("200 OK") > 0) {
                System.out.println(url + "----200，连接成功");
            } else {
                if (response1.getStatusLine().toString().indexOf("404 Not Found") > 0) {
                    System.out.println(url + "----404，连接失败");
                } else if (response1.getStatusLine().toString().indexOf("405 Method Not Allowed") > 0) {
                    System.out.println(url + "----405，连接失败");
                } else if (response1.getStatusLine().toString().indexOf("500 Internal Server Error") > 0) {
                    System.out.println(url + "----500，连接失败");
                } else {
                    System.out.println(url + "----未知状态，连接失败");
                }
            }
            HttpEntity entity1 = response1.getEntity();
            EntityUtils.consume(entity1);
        } finally {
            response1.close();
        }
    }


    private InvokeResultEntity invokeUrl(String url) throws Exception {
        InvokeResultEntity invokeResultEntity = new InvokeResultEntity();
        invokeResultEntity.setUrl(url);
        RequestConfig config = RequestConfig.custom()
                .setConnectTimeout(TIME_OUT * 1000)
                .setConnectionRequestTimeout(TIME_OUT * 1000)
                .setSocketTimeout(TIME_OUT * 1000).build();
        CloseableHttpClient httpclient =
                HttpClientBuilder.create().setDefaultRequestConfig(config).build();
        HttpGet httpGet = new HttpGet(url);
        CloseableHttpResponse response1 = httpclient.execute(httpGet);
        try {
            invokeResultEntity.setHttpCompleteStatus(response1.getStatusLine().toString());
            if (response1.getStatusLine().toString().indexOf("200 OK") > 0) {
                System.out.println(url + "----200,连接成功");
                invokeResultEntity.setHttpCode(HTTP_CODE_200);
                invokeResultEntity.setSuccess(true);
            } else {
                System.out.println(url + "----连接失败");
                invokeResultEntity.setSuccess(false);
                invokeResultEntity.setHttpCode(HTTP_CODE_UNKNOWN);
            }
            HttpEntity entity1 = response1.getEntity();
            EntityUtils.consume(entity1);
        } finally {
            response1.close();
        }
        return invokeResultEntity;
    }

    //对url的调用的核心函数
    //2个问题不靠谱：
    //1.synchronized用this去锁
    //2.用this.currentNum++,永远是1
    public void run() {
        try {
            synchronized (this) {
//                System.out.println(this);
                //写法一：借助外部力量
//                ClientProperties.setCurrentNum(ClientProperties.getCurrentNum()+1);
//                System.out.println("num为:"+ClientProperties.getCurrentNum());
//                ClientProperties.setUrl(ClientProperties.getPrefix() + ClientProperties.getCurrentNum());

                //写法二：比较倔强，自己就能搞定
                currentNum++;
//                System.out.println("num为:"+currentNum);
                ClientProperties.setUrl(ClientProperties.getPrefix() + currentNum);
                invokeUrl(ClientProperties.getUrl());
                Thread.sleep(100);//每搞完一次就睡眠100ms
            }
        } catch (Exception e) {
            //出现异常时只是打印一下信息，无需终止程序
            e.printStackTrace();
        }
    }


    /**
     * 对参数进行初始化
     */
    private void init(String[] args) {

        if (args == null) {
            throw new RuntimeException("参数不能为空");
        }


        if (args.length == 1) {
            ClientProperties.setPrefix(args[0]+"/?detectToken=");
            System.out.println("被侦察的URL前缀为:" + ClientProperties.getPrefix());
            System.out.println("线程数量为:" + ClientProperties.getThreadNums());
            return;
        }

        if (args.length > 2) {
            throw new RuntimeException("参数不能超过2");
        }

        ClientProperties.setPrefix(args[0]+"/?detectToken=");
        ClientProperties.setThreadNums(Integer.valueOf(args[1]));
        System.out.println("被侦察的URL前缀为:" + ClientProperties.getPrefix());
        System.out.println("线程数量为:" + ClientProperties.getThreadNums());
    }


}
